package cn.luo.config;

import cn.luo.entity.User;
import cn.luo.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableWebSecurity  //开启 过滤器功能
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    PasswordEncoder pe;

    @Autowired(required = false)
    UserService userService;

    @Autowired
    ObjectMapper objectMapper;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                System.out.println("username = " + username);
                User user = userService.findUserByName(username);
                //user.setPassword(pe.encode(user.getPassword()));   //加密数据库获取到的密码
                System.out.println("user = " + user);
                return user;
            }
        });
    }

    //静态资源 ，放行
    //ignoring  忽略
    // * 表示单前文件夹
    // ** 包括子文件夹
    @Override
    public void configure(WebSecurity web) throws Exception {
        //解决静态资源被拦截的问题
        web.ignoring().antMatchers("/css/**");
        web.ignoring().antMatchers("/js/**");
        web.ignoring().antMatchers("/img/**");
        web.ignoring().antMatchers("/api/login/**");
//        web.ignoring().antMatchers("/api/user/**");
//        web.ignoring().antMatchers("/api/**");
        //解决服务注册url被拦截的问题
        web.ignoring().antMatchers("/resources/**");

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().loginPage("/api/public/home")
             .loginProcessingUrl("/doLogin") //登录页面的请求
                //默认是 username 和 password
             .usernameParameter("username")
             .passwordParameter("password")

             .successHandler(new AuthenticationSuccessHandler() { //登录成功的处理
                 @Override
                 public void onAuthenticationSuccess(HttpServletRequest request,
                                                     HttpServletResponse response,
                                                     Authentication authentication)  //身份验证，当前用户登陆信息
                         throws IOException, ServletException {
                     System.out.println("登录成功" + authentication);
                     Object principal = authentication.getPrincipal();
                     System.out.println("登录成功-Authorities" + authentication.getAuthorities());
                     Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

                     response.setContentType("application/json;charset=utf-8");
                     PrintWriter out = response.getWriter();  //字符流输出
                     response.setStatus(200);  //状态码
                     Map<String,Object> map = new HashMap<>();
                     map.put("status",200);
                     map.put("code",0);
                     map.put("msg","登录成功");
                     for (GrantedAuthority authority : authorities) {
                         System.out.println("authority.getAuthority()=" + authority.getAuthority());
                         if (authority.getAuthority().contains("P")) {
                           map.put("action", "/api/public/home");
                         }
                         if (authority.getAuthority().contains("G")) {
                           map.put("action", "/api/public/home");
                         }
                     }
                     out.write(objectMapper.writeValueAsString(map));
                     out.flush();
                     out.close();
                 }
             })
             .failureHandler(new AuthenticationFailureHandler() {
                 @Override
                 public void onAuthenticationFailure(HttpServletRequest request,
                                                     HttpServletResponse response,
                                                     AuthenticationException exception)
                         throws IOException, ServletException {
                     System.out.println("登录失败");
                     response.setContentType("application/json;charset=utf-8");
                     PrintWriter out = response.getWriter();
                     response.setStatus(200);
                     Map<String, Object> map = new HashMap<>();
                     map.put("msg",0);
                     System.out.println("map = " + map);
                     out.write(objectMapper.writeValueAsString(map));
                     out.flush();
                     out.close();
                 }
             })
            .permitAll()
            .and()
            .logout()                   //开启注销登陆
            .logoutUrl("/logout")        //注销登陆请求url
            .clearAuthentication(true)    //清除身份信息
            .invalidateHttpSession(true)   //session失效
            .addLogoutHandler(new LogoutHandler() { //注销处理
                @Override
                public void logout(HttpServletRequest req,
                                   HttpServletResponse resp,
                                   Authentication auth) {

                }
            })
                .logoutSuccessHandler(new LogoutSuccessHandler() {     //注销成功处理
                    @Override
                    public void onLogoutSuccess(HttpServletRequest req,
                                                HttpServletResponse resp,
                                                Authentication auth)
                            throws IOException {
                        resp.sendRedirect("home");              //跳转到自定义登陆页面
                    }
                })
             .and()
             .authorizeRequests()      //所有浏览器请求
             .antMatchers("/api/public/**").permitAll()
             .antMatchers("/api/user/**").hasAuthority("P")
             .anyRequest().authenticated()  //任何的请求都要登录才能访问
             .and()
          .csrf().disable()   //禁止跨域
          .headers().frameOptions().sameOrigin();

    }
}
